home *** CD-ROM | disk | FTP | other *** search
- /* File: ScrapTools.c */
-
- #include <AppleEvents.h>
- #include "AERegistry.h"
- #include "AEObjects.h"
-
- #include "ScriptScrap.h"
- #include "Prototypes.h"
-
-
-
- OSErr _EntryToScrapIndex(short entryNum, short *scrapIndex, short *resID)
- {
- smapHand theSmap;
- short count, entriesSeen;
- OSErr err;
-
- /* The scrapbook map consists of an array of bytes, where the value of */
- /* each byte is either 0 (empty) or the number of some entry in the */
- /* scrapbook. (for example, the SMAP might begin with "[2, 0, 1, 0, …" */
- /* which indicates that the the first entry in the SMAP corresponds */
- /* with the second entry in the scrapbook, and the third entry in the */
- /* SMAP corresponds with the first entry in the scrapbook.) */
-
- /* Furthermore, each entry in the SMAP corresponds with the resource */
- /* number for the items that comprise that entry: SMAP[0] = resource ID */
- /* (-32768), SMAP[1] = resource(-32767), SMAP[2] = resource(-32766), */
- /* and so on. Therefore, we can get the resource ID for an item using */
- /* the following algorithm: */
- /* 1) Scan the table to find the entry whose value == entryNum */
- /* 2) resID == scrapIndex - 32768 */
-
- theSmap = (smapHand)Get1Resource('SMAP', 0);
- if (theSmap == 0L) return resNotFound;
- if ((err = ResError()) != noErr) return err;
-
- /* Convert the entry number into a scrap index */
- for (count = 0; count <= 255; count++)
- if ((**theSmap)[count] == entryNum) {
- /* We found it */
- *scrapIndex = count;
- *resID = count - 32768L;
- return noErr;
- }
-
- return errAENotAnElement; /* If we didn't find anything, exit */
- }
-
-
- OSErr _Get1ScrapItem(short resID, OSType itemType, AEDesc *item)
- /* Extract an entry from the scrapbook and put the result into an AEDesc */
- /* whose handle is a copy of the resource's handle and whose type == the */
- /* the resource's type. */
- {
- OSErr err;
-
- item->dataHandle = Get1Resource(itemType, resID);
- if (item->dataHandle == 0L) return resNotFound;
- if ((err = ResError()) != noErr) return err;
- item->descriptorType = itemType;
- HandToHand(&item->dataHandle); /* Copy the handle so we can close the resource */
- /* file or dispose of the AEDesc without a problem. */
- if ((err = MemError()) != noErr) {
- DisposHandle(item->dataHandle);
- item->dataHandle = 0L;
- }
- return err;
- } /* _Get1ScrapItem */
-
-
- OSErr CountScrapbookEntries(short *count)
- {
- smapHand theSmap;
- char *entryPtr;
- OSErr err;
- short index;
-
- *count = 0;
-
- theSmap = (smapHand)Get1Resource('SMAP', 0); /* The SMAP is the index to the resources */
- if (theSmap == 0L) return resNotFound; /* contained within the scrapbook file. */
- if ((err = ResError()) != noErr) return err;
-
- /* Count the entries */
- for (entryPtr = (char*)*theSmap, index = 0; index <= 255; index++, entryPtr++)
- if (*entryPtr != '\0') (*count)++;
-
- return noErr;
- }
-
-
- OSErr Get1ScrapbookItem (short entryIndex, ResType itemType, AEDesc *item)
- {
- /* This routine extracts all of the items of a given type from a scrapbook */
- /* entry. If itemType = typeWildCard then all of the items are extracted & */
- /* made into a list. */
- /* This routine stops if an error occurs and returns all of the entries */
- /* collected to that point. */
-
- AEDesc oneDesc;
- ResType oneType;
- short resID, smapIndex, numTypes, typeIndex, listIndex;
- OSErr err;
-
- /* Initialize the returned item, in case an error occurs */
- item->dataHandle = 0L;
- item->descriptorType = ' ';
-
- err = _EntryToScrapIndex(entryIndex, &smapIndex, &resID);
- if (err != noErr) return err;
-
- /* If we've been asked for a specific type, look for it */
- if (itemType != typeWildCard)
- return _Get1ScrapItem(resID, itemType, item);
- else {
- /* The user asked for everything in this item, so we'll look through all */
- /* available types for items with this resource number. */
- /* We have to do this because the scrapbook map gives no indication as */
- /* to which resource types are contained in a given scrapbook entry. */
- numTypes = CountTypes();
- for (typeIndex = 1, listIndex = 1; typeIndex <= numTypes; typeIndex++) {
- Get1IndType(&oneType, typeIndex);
- if ((err = ResError()) != noErr) return err;
- err = _Get1ScrapItem(resID, oneType, &oneDesc);
- if (err == noErr) {
- /* We have an item in oneDesc, so add it to the list */
- if (item->dataHandle == 0L) {
- /* But first, create the list if it doesn't exist */
- err = AECreateList(0L, 0, true /* isRecord */, item);
- if (err != noErr) return err;
- }
- Debugger();
- err = AEPutDesc(item, listIndex, &oneDesc);
- listIndex++;
- (void) AEDisposeDesc(&oneDesc); /* Get rid of the single entry whether */
- /* there was an error in AEPutDesc or not */
- if (err != noErr) return err;
- }
- /* Ignore "resNotFound" errors, since we are likely to get quite a few */
- /* of them as we try and find the resources for this one entry */
- if ((err != noErr) && (err != resNotFound)) return err;
- }
- }
- return noErr;
- } /* Get1ScrapbookEntry */
-
-
- OSErr Put1ScrapbookItem (short entryIndex, const AEDesc *entryContents)
- {
- /* This routine takes one or more resources (packaged as AEDescs with the */
- /* resource type in the descriptorType field and the resource handles in */
- /* the dataHandle field) and merges them into the specified entry. */
-
- OSErr err;
- short scrapIndex, listIndex, resID;
- Handle resHandle;
- long itemCount;
- AEDesc itemDesc;
- AEKeyword itemKeyword;
- smapHand theSmap;
- char *scrapbookMap;
- AEDescList entryList = {typeNull, NULL};
-
- /* Get the resource number for this scrapbook entry */
- err = _EntryToScrapIndex(entryIndex, &scrapIndex, &resID);
- if (err) goto done;
-
- /* Make sure that we have a list of items (since this routine can take either */
- /* a single item or a list. */
- err = AECoerceDesc(entryContents, typeAEList, &entryList);
- if (err != noErr) goto done;
-
- /* 1. Find out how many items we need to insert into this entry */
- err = AECountItems(&entryList, &itemCount);
- if (err != noErr) goto done;
- if (itemCount == 0) {
- err = errAEEventFailed; /* Can't continue if the list is empty */
- goto done;
- }
-
- /* 2. Add a resource for each of the list items, replacing any resources which may */
- /* already exist there. */
- for (listIndex = 1; listIndex <= itemCount; listIndex++) {
- err = AEGetNthDesc(&entryList, listIndex, typeWildCard, &itemKeyword, &itemDesc);
- if (err != noErr) goto done;
- /* remove any copies of this resource that may already exist */
- do {
- resHandle = Get1Resource(itemDesc.descriptorType, resID);
- if (resHandle != 0L) {
- RmveResource(resHandle);
- if ((err = ResError()) != noErr) goto done;
- DisposHandle(resHandle);
- }
- } while (resHandle != 0L);
-
- /* Create a new resource */
- AddResource(itemDesc.dataHandle, itemDesc.descriptorType, resID, "\p");
- WriteResource(itemDesc.dataHandle);
- if ((err = ResError()) != noErr) goto done;
- ReleaseResource(itemDesc.dataHandle); /* We don't need to keep this resource */
- /* in memory. */
- /* We don't need to dispose of the AEDesc since the handle has been converted */
- /* into a resource, and ReleaseResource disposed of it for us. */
- }
-
- done:
- if (entryList.dataHandle != NULL)
- (void) AEDisposeDesc(&entryList);
- return err;
- } /* Put1ScrapbookItem */
-
-
- OSErr InsertScrapbookEntry (short entryNum, const AEDescList *itemList)
- {
- /* This adds a new entry to the scrapbook file before the entry specified by */
- /* "entryNum". */
- smapHand theSmap;
- char *slotPtr;
- short slotNum, resID;
- OSErr err;
- unsigned char slotMap[33] = {0}; /* Add 1 extra byte of zeroes at the end as a guard }
-
- /* Find an emply slot in the smap */
- theSmap = (smapHand)Get1Resource('SMAP', 0);
- if (theSmap == 0L) return resNotFound;
- if ((err = ResError()) != noErr) return err;
-
- /* Look for the first non-zero slot */
- for (slotNum = 0, slotPtr = (char *)*theSmap; /* Initial conditions */
- (*slotPtr != '\0') && (slotNum <= 255); /* test */
- slotNum++, slotPtr++) ; /* repeat while test == true */
-
- if (slotNum > 255)
- return errAEWriteDenied; /* We're out of slots */
-
-
- resID = slotNum - 32768L; /* Calculate a resource ID */
-
- /* Adjust all of the subsequent entry numbers upwards and claim our slot */
- err = AdjustScrapbookEntries(entryNum, true);
- if (err != noErr) return err;
- **theSmap[slotNum] = entryNum;
-
- /* Store the information we've been passed */
- if (itemList->dataHandle != 0L)
- err = Put1ScrapbookItem(entryNum, itemList);
-
- return err;
- } /* InsertScrapbookEntry */
-
-
- OSErr _Delete1ScrapItem(short resID, OSType itemType)
- /* Remove a resource with a particular type and ID from the scrapbook file */
- {
- OSErr err = noErr;
- Handle resHandle;
-
- while (true) {
- /* Remove each instance of this resource */
- resHandle = Get1Resource(itemType, resID);
- if (resHandle == 0L) break;
- if ((err = ResError()) != noErr) break;
- RmveResource(resHandle);
- DisposHandle(resHandle);
- if ((err = ResError()) != noErr) break;
- };
- return err;
- } /* _Delete1ScrapItem */
-
-
-
- OSErr AdjustScrapbookEntries(short startValue, Boolean adjustUpwards)
- {
- /* This is used to adjust entry numbers in the scrapbook when an entry is */
- /* inserted or deleted. If you want to insert an item in front of entry n, */
- /* then you call this with (n, true) and entry n becomes n+1, n+1 becomes */
- /* n+2, etc. If you want to delete entry n, you delete and zero the SMAP */
- /* entry, and then call this with either n or n+1 and "false". Entry n+1 */
- /* will become entry n, entry n+2 will become n+1, etc. */
-
- smapHand theSmapHand;
- OSErr err;
- short count;
- char *entryPtr;
-
- if ((startValue <= 0) || (startValue >= 256))
- return errAENoSuchObject;
- theSmapHand = (smapHand)Get1Resource('SMAP', 0); /* The SMAP is the index to the resources */
- if (theSmapHand == 0L) return resNotFound; /* contained within the scrapbook file. */
- if ((err = ResError()) != noErr) return err;
-
- for (count = 0, entryPtr = (char *)*theSmapHand; count <= 255; count++, entryPtr++)
- if (*entryPtr >= startValue) {
- if (adjustUpwards)
- (*entryPtr) += 1;
- else
- (*entryPtr) -= 1;
- }
- ChangedResource((Handle)theSmapHand);
- if ((err = ResError()) != noErr) return err;
- WriteResource((Handle)theSmapHand);
- err = ResError();
-
- return err;
- }
-
-
- OSErr ZeroScrapbookIndex(short smapIndex)
- {
- /* This is called when all of the elements of th item at "smapIndex" have been */
- /* deleted. It removes that item's entry from the scrapbook map. */
- smapHand theSmap;
- OSErr err;
-
- theSmap = (smapHand)Get1Resource('SMAP', 0); /* The SMAP is the index to the resources */
- if (theSmap == 0L) return resNotFound; /* contained within the scrapbook file. */
- if ((err = ResError()) != noErr) return err;
-
- (**theSmap)[smapIndex] = 0;
-
- ChangedResource((Handle)theSmap);
- err = ResError();
-
- return err;
- }
-
-
- OSErr Delete1ScrapbookItem (short entryIndex, OSType itemType, Boolean *entryRemoved)
- {
- /* Delete the item of the given type from the given scrapbook entry */
- /* If itemType == typeWildCard, then all entries are deleted for that */
- /* entry. */
- ResType oneType;
- short resID, smapIndex, numTypes, typeIndex;
- Handle dummyHandle;
- OSErr err;
-
-
- numTypes = Count1Types(); /* We'll use this to 1) scan all types on a "delete all" */
- /* request and 2) scan all types to see if any entries */
- /* remain on a "delete 1 type" request. */
-
- *entryRemoved = false;
- err = _EntryToScrapIndex(entryIndex, &smapIndex, &resID);
- if (err == noErr) {
- /* If we've been asked for a specific type, look for it */
- if (itemType != typeWildCard) {
- err = _Delete1ScrapItem(resID, itemType);
- if (err != noErr) return err;
-
- /* Now, see if no more resources exist for this scrapbook entry */
- /* If so, we can zero the corresponding entry in the resource */
- /* map. */
- SetResLoad(false); /* We just want to know if the resources exist */
- for (typeIndex = 1; typeIndex <= numTypes; typeIndex++) {
- Get1IndType(&oneType, typeIndex);
- if ((err = ResError()) != noErr) break;
- (void) Get1Resource(oneType, resID); /* (void) == ignore the returned handle */
- if ((err = ResError()) != resNotFound) break;
- /* That's not a typo -- Exit the loop if a */
- /* resource was found or some other error */
- /* occurred. */
- }
- SetResLoad(true);
- if (err == resNotFound) {
- /* No resources were found, so we can remove this entry */
- err = ZeroScrapbookIndex(smapIndex);
- if (err != noErr) return err;
- err = AdjustScrapbookEntries(entryIndex, false);
- *entryRemoved = true;
- }
- }
-
- else {
- /* The user asked for everything in this item, so we'll look through all */
- /* available types for items with this resource number. */
- for (typeIndex = 1; typeIndex <= numTypes; typeIndex++) {
- Get1IndType(&oneType, typeIndex);
- if ((err = ResError()) != noErr) break;
- SetResLoad(false);
- dummyHandle = Get1Resource(oneType, resID);
- SetResLoad(true);
- if (dummyHandle != NULL) {
- err = _Delete1ScrapItem(resID, oneType);
- if (err != noErr) return err;
- }
- }
- /* Since we deleted all of this items, remove this entry */
- if (err == noErr) {
- *entryRemoved = true;
- err = ZeroScrapbookIndex(smapIndex);
- if (err != noErr) return err;
- err = AdjustScrapbookEntries(entryIndex, false);
- }
- }
- }
- return err;
- } /* Delete1ScrapbookItem */
-
-
- /* Since the "best type" for a given scrapbook entry varies depending on */
- /* what's in that entry, we've written the following routine to find the */
- /* best type for a given entry. The algorithm is as follows: */
- /* 1) Search for elements of a particular type, in descending order */
- /* of preference. */
- /* 2) If we find something, return that item's type code. If we */
- /* don't, then return the type code for the first item. */
-
- OSErr GetBestType(short entryNum, ResType *bestType)
- {
- OSErr err = noErr;
- ResType preferredTypes[3] = {'PICT', 'TEXT', 'snd '};
- short scrapIndex, resID, scratch;
- Handle dummyHandle;
- short count;
-
- err = _EntryToScrapIndex(entryNum, &scrapIndex, &resID);
- if (err != noErr) return err;
-
- /* First, we'll try for one of our preferred types */
- SetResLoad(false); /* We only want to know if particular resources exist, */
- /* but we don't want to load them here. */
- for (count = 0; count <= 2; count++) {
- dummyHandle = Get1Resource(preferredTypes[count], resID);
- if (dummyHandle != NULL) {
- /* This resource exists, so return its type code */
- *bestType = preferredTypes[count];
- SetResLoad(true);
- return noErr;
- }
- }
- SetResLoad(true);
-
- /* If the above test fails, then we don't have a recognized type, so we'll */
- /* take the first type we can get. */
- scratch = 1;
- return GetAllTypes(entryNum, &scratch, bestType);
- }
-
- /* Get a list of all of the resource types contained in entry "entryNum" */
- /* On entry, typeList is the address of an array of resource types, and */
- /* numSlots is the number of openings in that array. On exit, numSlots */
- /* is the number of type codes that were placed in the array. */
-
- OSErr GetAllTypes(short entryNum, short *numSlots, ResType *typeList)
- {
- short lastSlot = *numSlots;
- OSErr err;
- short scrapIndex, resID;
- short numTypes, typeCount;
- ResType typeCode;
- Handle dummyHandle;
-
- *numSlots = 0;
- err = _EntryToScrapIndex(entryNum, &scrapIndex, &resID);
- if (err != noErr) return err;
-
- numTypes = CountTypes();
- SetResLoad(false); /* We only want to know if particular resources exist, */
- /* but we don't want to load them here. */
- for (typeCount = 1; typeCount <= numTypes; typeCount++) {
- Get1IndType(&typeCode, typeCount);
- if ((err = ResError()) != noErr) break;
- dummyHandle = Get1Resource(typeCode, resID);
- if (dummyHandle != NULL) {
- /* This resource exists, so add it to the list */
- typeList[*numSlots] = typeCode;
- ++(*numSlots);
- if (*numSlots >= lastSlot) break; /* Exit this loop */
- }
- }
- SetResLoad(true);
-
- return err;
- }
-
-
-